#include "fxcc/core/graph/opengl3/ImGuiGlfwApp.h"
#include "fxcc/core/graph/common/Geometry.h"
#include "fxcc/core/graph/common/BoneNode.h"

#include "fxcc/core/graph/common/Scene.h"
#include "fxcc/core/graph/opengl3/Resources.h"
#include "fxcc/core/graph/opengl3/SSBO.h"

#include "fxcc/imgui/Editor.h"

using namespace fxcc::platform;
using namespace fxcc::graph;
using namespace fxcc::graph::opengl3;
using namespace fxcc::imgui::graph::opengl3;
using BaseApp = fxcc::imgui::graph::opengl3::GlfwApp;

#undef main

struct SimpleApp : public BaseApp
{
public:


    SimpleApp(const fxcc::platform::common::App::Desc& desc) : BaseApp(desc)
    {
    }
    bool Init() override
    {
        if (!BaseApp::Init())
        {
            return false;
        }

        if (!InitResources())
        {
            return false;
        }

        return true;
    };

    void printOpenGLESVersion()
    {
        const char* version = (const char*)glGetString(GL_VERSION);
        std::cout << "OpenGL ES Version: " << version << std::endl;
    };

    bool InitResources()
    {
        const int dataSize = 1024;
        std::vector<float> inputData(dataSize);
        std::vector<float> outputData(dataSize);

        for (int i = 0; i < inputData.size(); i++)
        {
            inputData[i] = (float)i;
        }
     
        const char* computeShaderSrc = R"(

layout(std430, binding = 0) buffer DataBuffer1 {
    float inputData[];
};
layout(std430, binding = 1) buffer DataBuffer2 {
    float outputData[];
};

layout(local_size_x = 256) in;
void main() {
    uint id = gl_GlobalInvocationID.x;
    outputData[id] = inputData[id] * inputData[id];
}
)";
        auto effect = std::make_shared<ComputeEffect>(computeShaderSrc);


        auto ssbo = std::make_shared<SSBO>();
        ssbo->Bind();
        ssbo->BufferData<float>(inputData, GL_DYNAMIC_DRAW);
        ssbo->BufferDataBase(0);

        auto ssbo2 = std::make_shared<SSBO>();
        ssbo2->Bind();
        ssbo2->BufferData<float>(outputData, GL_DYNAMIC_DRAW);
        ssbo2->BufferDataBase(1);

        effect->Begin();

        effect->DispatchCompute((dataSize + 255) / 256, 1, 1);

        fxcc::graph::opengl3::SSBO::MemoryBarrier();

        //glBindBuffer(GL_SHADER_STORAGE_BUFFER, outputSSBO);
        //glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, bufferSize, outputData.data());
        ssbo2->Bind();
        ssbo2->GetBufferSubDataType<float>(outputData);

        for (const auto& i : outputData)
        {
            ztclog::info("^2 is %f", i);
        }

        //float* outputData = ssbo->MapData<float>();

        //for (int i = 0; i < 10; i++) {
        //    //std::cout << "data[" << i << "] = " << outputData[i] << std::endl;
        //    ztclog::info("index %d value %f", i, outputData[i]);
        //}

        //ssbo->UnMap();
        return true;
    };

    fxcc::imgui::Editor editor;
    ;

    void OnEdit() override
    {
        ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport());

    }
    void OnDestroy() override
    {

        BaseApp::OnDestroy();
    }
    void OnFrameRender() override
    {
        
    };

    void OnFramebuffersize(int w, int h) override
    {
        opengl3::GlfwApp::OnFramebuffersize(w, h);

    }
    void OnUpdate() override
    {
        opengl3::GlfwApp::OnUpdate();

        float ctTime = m_GlfwlTimer.m_CurrentTime;

        float deltaTime = m_GlfwlTimer.m_DeltaTime;

    }
};

int main()
{
    ztclog::pushFunction([](const ztclog::Line& line)
        {
            if (line.m_Type != ztclog::Line::Type::_line_debug_)
            {
                std::cout << line.m_Text << std::endl;
            } });

            using _App = SimpleApp;
            using _Desc = fxcc::platform::common::App::Desc;

            _Desc desc;
            desc.m_Pos = glm::ivec2(100, 100);
            desc.m_Size = glm::ivec2(900, 600);
            desc.m_ScaleFactor = 1.0f;

            desc.m_Title = "test font";
            std::shared_ptr<_App> _app = std::make_shared<_App>(desc);
            return _app->Run();
};
